
#include <BStream>
#include <BHtmlItem>
#include <BSonNode>
#include "member_BSonNode.h"

using namespace BWE;

#define member					(*(member_BSonNode*)_ptr)
#define member_allocate()		_ptr = new member_BSonNode(this)
#define member_release()		delete (member_BSonNode*)_ptr

BSonNode::BSonNode(BSonNode* parent)
{
	member_allocate();
	setParent(parent);
}
BSonNode::BSonNode(const BString& name, BSonNode* parent) : BObject(name)
{
	member_allocate();
	setParent(parent);
}
BSonNode::~BSonNode()
{
	member_release();
}

bool BSonNode::setFormat(const BString& format)
{
	if (member.format.text != format)
	{
		member.format.fromString(format);
		return true;
	}
	return true;
}
const BString& BSonNode::format() const
{
	return member.format.text;
}

bool BSonNode::setText(const BString& text)
{
	if (member.text != text)
	{
		member.text = text;
		member.text.trimmed();
	}
	return true;
}
const BString& BSonNode::text() const
{
	return member.text;
}

void BSonNode::setAttribSet(const BMap<BString, BString>& attribSet)
{
	member.attribMap = attribSet;
}
const BMap<BString, BString>& BSonNode::attribSet() const
{
	return member.attribMap;
}

bool BSonNode::setAttrib(const BString& name, const BString& value)
{
	if (name.empty())
		return false;
	member.attribMap[name] = value;
	return true;
}
const BString& BSonNode::attrib(const BString& name) const
{
	return member.attribMap(name);
}
bool BSonNode::containAttrib(const BString& name) const
{
	return member.attribMap.contain(name);
}
bool BSonNode::removeAttrib(const BString& name)
{
	return member.attribMap.remove(name);
}
void BSonNode::clearAttribs()
{
	member.attribMap.clear();
}

const BSonNode* BSonNode::root() const
{
	const BSonNode* node = this;
	while (son_member(node)->parent)
		node = son_member(node)->parent;
	return node;
}
BSonNode* BSonNode::root()
{
	BSonNode* node = this;
	while (son_member(node)->parent)
		node = son_member(node)->parent;
	return node;
}

void BSonNode::setParent(BSonNode* parent)
{
	if (parent && parent != this)
	{
		parent->addChild(this);
	}
}
BSonNode* BSonNode::parent()
{
	return member.parent;
}
const BSonNode* BSonNode::parent() const
{
	return member.parent;
}
BSonNode* BSonNode::parent(const BString& name)
{
	if (name.empty())
		return 0;
	BSonNode* parent = member.parent;
	while (parent && parent->name() != name)
		parent = son_member(parent)->parent;
	return parent;
}
const BSonNode* BSonNode::parent(const BString& name) const
{
	if (name.empty())
		return 0;
	const BSonNode* parent = member.parent;
	while (parent && parent->name() != name)
		parent = son_member(parent)->parent;
	return parent;
}

BSonNode* BSonNode::addChild(const BString& name, const BString& text)
{
	BSonNode* child = new BSonNode(name);
	member.children.append(child);
	son_member(child)->parent = this;
	son_member(child)->text = text;
	return child;
}
bool BSonNode::addChild(BSonNode* child)
{
	if (!child)
		return false;
	if (child == this)
		return false;
	if (child == member.parent)
		return false;
	if (!member.children.contain(child))
	{
		member.children.append(child);
		if (son_member(child)->parent)
			son_member(child)->parent->remove(child);
		son_member(child)->parent = this;
		return true;
	}
	return false;
}

bool BSonNode::insertChild(int pos, BSonNode* node)
{
	if (!node)
		return false;
	if (node == this)
		return false;
	if (node == member.parent)
		return false;
	if (member.children.insert(pos, node))
	{
		if (son_member(node)->parent)
			son_member(node)->parent->removeChild(node);
		son_member(node)->parent = this;
		return true;
	}
	return false;
}
bool BSonNode::removeChild(const BSonNode* node)
{
	if (!node)
		return false;
	if (node == this)
		return false;
	if (node == member.parent)
		return false;
	if (son_member(node)->parent == this)
	{
		son_member(node)->parent = 0;
		member.children.remove(node);
		return true;
	}
	return false;
}

void BSonNode::remove(BSonNode* child)
{
	if (child && member.children.contain(child))
	{
		son_member(child)->parent = 0;
		member.children.remove(child);
	}
}
void BSonNode::remove(const BString& desc)
{
	if (desc.contain(':') || desc.contain('&') || desc.contain('|'))
	{
		SonFilter filter(desc);
		for (int i = 0; i < member.children.size(); i++)
		{
			BSonNode* child = member.children[i];
			if (filter(child))
			{
				son_member(child)->parent = 0;
				member.children.remove(i--);
			}
		}
	}
	else
	{
		for (int i = 0; i < member.children.size(); i++)
		{
			BSonNode* child = member.children[i];
			if (child->name() == desc)
			{
				son_member(child)->parent = 0;
				member.children.remove(i--);
			}
		}
	}
}
void BSonNode::clear()
{
	for (int i = 0; i < member.children.size(); i++)
	{
		BSonNode* child = member.children[i];
		son_member(child)->parent = 0;
	}
	member.children.clear();
}

int BSonNode::childCount() const
{
	return member.children.size();
}
BSonNode* BSonNode::child(int index)
{
	return member.children(index);
}
const BSonNode* BSonNode::child(int index) const
{
	return member.children(index);
}

BSonNode* BSonNode::child(const BString& desc)
{
	if (desc.contain(':') || desc.contain('&') || desc.contain('|'))
	{
		SonFilter filter(desc);
		for (int i = 0; i < member.children.size(); i++)
		{
			BSonNode* child = member.children[i];
			if (filter(child))
				return child;
		}
	}
	else
	{
		for (int i = 0; i < member.children.size(); i++)
		{
			BSonNode* child = member.children[i];
			if (child->name() == desc)
				return child;
		}
	}
	return 0;
}
const BSonNode* BSonNode::child(const BString& desc) const
{
	if (desc.contain(':') || desc.contain('&') || desc.contain('|'))
	{
		SonFilter filter(desc);
		for (int i = 0; i < member.children.size(); i++)
		{
			BSonNode* child = member.children[i];
			if (filter(child))
				return child;
		}
	}
	else
	{
		for (int i = 0; i < member.children.size(); i++)
		{
			BSonNode* child = member.children[i];
			if (child->name() == desc)
				return child;
		}
	}
	return 0;
}

BSonNode* BSonNode::find(const BString& desc)
{
	if (desc.contain(':') || desc.contain('&') || desc.contain('|'))
	{
		SonFilter filter(desc);
		BSonNode* node = member.find(filter);
		return node;
	}
	else
	{
		if (this->name() == desc)
			return this;
		for (int i = 0; i < member.children.size(); i++)
		{
			BSonNode* child = member.children[i];
			BSonNode* node = child->find(desc);
			if (node)
				return node;
		}
	}
	return 0;
}
const BSonNode* BSonNode::find(const BString& desc) const
{
	if (desc.contain(':') || desc.contain('&') || desc.contain('|'))
	{
		SonFilter filter(desc);
		for (int i = 0; i < member.children.size(); i++)
		{
			BSonNode* child = member.children[i];
			BSonNode* node = child->find(desc);
			if (node)
				return node;
		}
	}
	else
	{
		if (this->name() == desc)
			return this;
		for (int i = 0; i < member.children.size(); i++)
		{
			BSonNode* child = member.children[i];
			BSonNode* node = child->find(desc);
			if (node)
				return node;
		}
	}
	return 0;
}

int BSonNode::index() const
{
	if (member.parent)
	{
		BArray<BSonNodeHolder>& up_children = son_member(member.parent)->children;
		for (int i = 0; i < up_children.size(); i++)
		{
			if (up_children[i] == this)
				return i;
		}
	}
	return -1;
}
bool BSonNode::empty() const
{
	return member.text.empty() && member.attribMap.empty() && member.children.empty();
}
int BSonNode::level() const
{
	int count = 0;
	BSonNode* parent = member.parent;
	while (parent)
	{
		parent = son_member(parent)->parent;
		count++;
	}
	return count;
}

BSonNode* BSonNode::prev()
{
	if (member.parent)
	{
		BArray<BSonNodeHolder>& up_children = son_member(member.parent)->children;
		int index = up_children.find(this);
		if (index > 1)
			return up_children[index - 1];
	}
	return 0;
}
BSonNode* BSonNode::next()
{
	if (member.parent)
	{
		BArray<BSonNodeHolder>& up_children = son_member(member.parent)->children;
		int index = up_children.find(this);
		if (index < up_children.size() - 1)
			return up_children[index + 1];
	}
	return 0;
}

BSonNode* BSonNode::locate(const BString& desc)
{
	BStringList namelst = desc.split('/');
	BSonNode* node = this->child(namelst.first());
	namelst.remove(0);
	while (node && namelst.size())
	{
		const BString& text = namelst.first();
		node = node->child(text);
		namelst.remove(0);
	}
	return node;
}
